import asyncio
import time
import threading
import socket

from .router import Router
from .tool import *
from .const import *
from .web_object import *


class Express(Router):
    ''' Express框架的核心类, 用于创建Web服务器并管理路由和中间件 '''
    def __init__(self, ip='0.0.0.0', port=None, maxConnectCount=100):
        ''' 初始化Express实例, 设置默认配置和属性 '''
        super().__init__()
        # 保存服务端的socket对象
        self._tcpServer = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        # 设置默认的IP地址和端口号
        self.ip = ip
        self.port = port
        # 设置默认的连接数限制
        self.maxConnectCount = maxConnectCount
    
    async def _handler(self, tcp_conn, tcp_addr, conn_time):
        ''' 加载请求并引导进入中间件层的处理函数 '''
        # 获取请求和响应对象
        req = HttpRequest(tcp_conn, tcp_addr, conn_time)
        res = HttpResponse(tcp_conn)
        # 进入中间件层的调用
        if req.success:
            await self.middleware_handler(req, res)
        # 关闭连接表示中间件层处理完毕
        tcp_conn.close()

    def listen(self, port):
        ''' 用于设置服务器监听的端口 '''
        self.port = port

    def start_async_server(self):
        ''' 开启异步服务器 '''
        # 创建一个socket对象
        try:
            print('正在启动服务器')
            # 设置socket的选项，允许重用地址
            self._tcpServer.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
            # 绑定IP地址和端口号
            self._tcpServer.bind((self.ip, self.port))
            # 开始监听
            self._tcpServer.listen(self.maxConnectCount)
        except Exception as e:
            # 一般是端口占用才会报这个错误
            print(e)
            return
        print(f'Server is running on port {self.port}')
        print("【 Start server 】", formatTime(time.time()))

        # 循环监听tcp连接
        while True:
            try:
                # 获取客户端的连接
                tcpConn, tcpAddr = self._tcpServer.accept()
                connTime = time.time()
                tcpConn.setblocking(False)   # 接收数据设置为非阻塞
                # 创建一个协程对象
                new_task = self._handler(tcpConn, tcpAddr, connTime)
                asyncio.run_coroutine_threadsafe(new_task, self.loop)
            except Exception as e:
                print(e)
                continue

    def start(self):
        ''' 启动服务器 '''
        # 主线程创建事件循环
        loop = asyncio.new_event_loop()
        asyncio.set_event_loop(loop)
        self.loop = loop
        # 守护线程接收请求
        threading.Thread(target=self.start_async_server, daemon=True).start()
        # 主线程维持事件循环
        try:
            print("Main thread event loop running...")
            loop.run_forever()
        except KeyboardInterrupt:
            print("【 KeyboardInterrupt 】 Event loop stopped by user.")
            print("【 End server 】", formatTime(time.time()))
        finally:
            loop.close()